package org.dbp.filtro;

import java.beans.PropertyEditorSupport;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.dbp.error.ErrorDbpUtils;
import org.dbp.error.exception.ExceptionDbp;
import org.dbp.filtro.bean.FiltroCriterio;
import org.dbp.registros.AlmacenRegistrosDbp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 
 * Esta clase es la encarga de realizar las operaciones de filtrar elementos.
 *
 * Clases primitivas validas:
 * 	BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short
 *  String
 *  Date,Time,Timestamp
 *  
 *  Para que un campo se le puede aplciar un criterio de filtro es necesario que cumpla las siguientes condiciones.
 *    - Que el tipo de datos implementa la interfaz de comparable. 
 *    - Que tenga un propertyEntitySuport, para poder pasar de objeto a cadena de texto.
 *    - Que el propertyEntitySuport, este añadido a la cache donde estan registros asociada a la clase que representa.
 * 
 * @author David Blanco París
 *
 * @param <T>	Es la entidad que implementa la operaci�n de filtrar.
 * @param <O>	Es la clase que implementa lo que vamos hacer cuando filtremos.
 */
public class OperacionFiltrar <T extends Serializable,O extends IOperacionFiltrar<T>> {
	
	private static Logger logger = LoggerFactory.getLogger(OperacionFiltrar.class);
	
	public static String mensajeErrorObtenerValorRegistroVacio="operacionfiltrar.mensaje.error.obtenerValorRegistroVacio"; 
	public static String mensajeErrorObtenerValorClaseVacia="operacionfiltrar.mensaje.error.obtenerValorNoHayClase";
	public static String mensajeErrorObtenerValorNoEncontradaLaClase="operacionfiltrar.mensaje.error.obtenerValorNoEncontradaLaClase";
	
	public static String mensajeErrorFiltrarCampoNoHayCriterios="operacionfiltrar.mensaje.error.filtrarCampoNoHayCriterio";
	public static String mensajeErrorFiltrarCampoNoHayOperacion="operacionfiltrar.mensaje.error.filtrarCampoNoHayOperacion";
	
	public static String mensajeErrorFiltrarObtenerElCampo="operacionfiltrar.mensaje.error.filtrarObtenerElcampo";
	public static String mensajeErrorFiltrarObtenerCampoNoValido="operacionfiltrar.mensaje.error.filtrarCampoNoValido";
	public static String mensajeErrorFiltrarCriteriosNoValidos="operacionfiltrar.mensaje.error.filtrarCampoCriteriosNoValidos";
	
	public static String mensajeErrorFiltrarCriteriosOperacionRelacionalNoValida="operacionfiltrar.mensaje.error.filtrarOperacionRelacionalNoValido";
	
	public static String mensajeErrorProcesarFiltrarNullObjetoFiltrado="operacionfiltrar.mensaje.error.procesarFiltrarNulObjetoFiltrado";
	public static String mensajeErrorProcesarFiltrarErrorInstanciarElementoNuevo="operacionfiltrar.mensaje.error.procesarFiltrarErrorInstanciarElementoNuevo";
	public static String mensajeErrorProcesarFiltrarFlagElementoNuevo="operacionfiltrar.mensaje.error.procesarFiltrarFlagaElementoNuevo";
	
	private O operacionFiltrar;

	public OperacionFiltrar(O operacionFiltrar) {
		super();
		this.operacionFiltrar = operacionFiltrar;
	}
	
	/**
	 * 
	 * Lanzamos unos criterios sobre las lineas.
	 * 
	 * Nota: Cargamos unos registros estandar.
	 * 
	 * @param lineas		Las lineas que vamos a filtrar.
	 * @param criterios		Los criterios con los que vamos a filtrar.
	 * @return				
	 * @throws ExceptionDbp		
	 */
	
	public List<T> filtrar(List<T> lineas, List<FiltroCriterio> criterios) throws ExceptionDbp{
		return filtrar(lineas,criterios,false);
	}
	
	/**
	 * 
	 * Lanzamos unos criterios sobre las lineas.
	 * 
	 * Nota: Cargamos unos registros estandar.
	 * 
	 * @param lineas		Las lineas que vamos a filtrar.
	 * @param criterios		Los criterios con los que vamos a filtrar.
	 * @param lineasNuevas	Se encarga de crear un listado nuevo ( Se apolla en la operación de clonar.
	 * @return				
	 * @throws ExceptionDbp		
	 * 
	 * 
	 */
	public List<T> filtrar(List<T> lineas, List<FiltroCriterio> criterios,Boolean lineasNueva) throws ExceptionDbp{
		return filtrar(lineas,criterios,lineasNueva,AlmacenRegistrosDbp.obtenerInstancia().obtenerMapeoComparables());
	}
	
	/** 
	 * 
	 * Lanzamos unos criterios sobre las lineas.
	 * 
	 * Nota: Cargamos unos registros estandar.
	 * 
	 * @param lineas		Las lineas que vamos a filtrar.
	 * @param criterios		Los criterios con los que vamos a filtrar.
	 * @param registros		Se encarga de crear los registros.
	 * @return				
	 * @throws ExceptionDbp		
	 * 
	 * 
	 */
	public List<T> filtrar(List<T> lineas,List<FiltroCriterio> criterios,Map<Class,PropertyEditorSupport> registros) throws ExceptionDbp{
		return filtrar(lineas,criterios,false,registros);
	}
	
	/**
	 * 
	 * Lanzamos unos criterios sobre las lineas.
	 * 
	 * @param lineas		Las lineas que vamos a filtrar.
	 * @param criterios		Los criterios con lo que vamos a filtrar.
	 * @param listaNueva	Si creamos una lista nueva con el resultado del filtrado.
	 * @param registros		La cache con los registros con los que vamos a trabajar.
	 * @return
	 * @throws ExceptionDbp
	 */
	public List<T> filtrar(List<T> lineas,List<FiltroCriterio> criterios,Boolean listaNueva,Map<Class,PropertyEditorSupport> registros) throws ExceptionDbp{
		List<T> valdev=lineas;
		if(lineas==null || lineas.size()==0){
			logger.debug("No vamos aplicar los filtros, por que no hay lineas para ser filtradas. ");
		}else{
			if(listaNueva){
				valdev= new ArrayList<T>();
				for(T linea:lineas){
					valdev.add(procesarFiltrado(linea,criterios,listaNueva,registros));
				}
			}else{
				for(T linea:valdev){
					procesarFiltrado(linea,criterios,listaNueva,registros);
				}
			}
		}
		return valdev;
	}
	
	/**
	 * 
	 * Realizamos la operación de filtrado, por un lado, mira si se cumplen los criterios de filtrado y si es asi ejecuta la operación de filtro.
	 * 
	 * @param elemento		El elemento que vamos a filtrar.
	 * @param criterios		La lista de criterios, que vamos aplicar par los filtros.
	 * @param registros		Los registros con lso que vamos a trabajar.
	 * @throws ExceptionDbp	
	 * 	Controla que exista la operacion de filtrado
	 */
	protected T procesarFiltrado(T elemento,List<FiltroCriterio> criterios,Boolean elementoNuevo,Map<Class,PropertyEditorSupport> registros) throws ExceptionDbp{
		T valdev=inicializarElElemento(elemento, elementoNuevo);
		if(operacionFiltrar==null){
			ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
					mensajeErrorProcesarFiltrarNullObjetoFiltrado,operacionFiltrar);
		}else if(filtrar(elemento,criterios,registros)){
			valdev=operacionFiltrar.operacionFiltrado(valdev);
		}else{
			valdev=operacionFiltrar.operacionNoFiltrado(valdev);
		}
		return valdev;
	}
	/**
	 * 
	 * Se encarga de inicalizar el elemento.
	 * 
	 * 	- Se encarga de crear el elemento si procede.
	 * 
	 * @param elemento			El elemento con el que vamos a trabajar.
	 * @param elementoNuevo		Se encarga elemento nuevo.
	 * @return
	 * @throws ExceptionDbp
	 */
	private T inicializarElElemento(T elemento, Boolean elementoNuevo)
			throws ExceptionDbp {
		T valdev=null;
		if(elementoNuevo==null){
			logger.warn("Para poder procesar el filtro es obligatorio que este el flag del elemento nuevo [{}]",elementoNuevo);
			ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
					mensajeErrorProcesarFiltrarFlagElementoNuevo,elementoNuevo);
		}else if(elementoNuevo){
			try {
				valdev=operacionFiltrar.clonarElemento(elemento);
			} catch (Exception e) {
				logger.error("A la hora de instanciar un nuevo elemento se ha creado [{}]",e.getMessage(),e);
				ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
						mensajeErrorProcesarFiltrarErrorInstanciarElementoNuevo,elemento!=null?elemento.getClass().getSimpleName():elemento);
			}
		}else{
			valdev=elemento;
		}
		return valdev;
	}
	
	
	
	/**
	 * 
	 * Se encarga de mirar si el elementos cumple los criterios.
	 * 
	 * Nota, si no tiene elemento o criterio, la operacion se filtra.
	 * 
	 * Si el valor del filtro es null o vacio, la operación falta el filtro, de todos modos esto es revisable.
	 * 
	 * @param elemento
	 * @param criterios
	 * @param registros
	 * @return
	 * @throws ExceptionDbp
	 */
	protected Boolean filtrar(T elemento,List<FiltroCriterio> criterios,Map<Class,PropertyEditorSupport> registros) throws ExceptionDbp{
		Boolean valdev=false;
		if(elemento==null){
			logger.debug(" Se aplica el filtro automaticamente si no existe la tupla [{}]",elemento);
			valdev=true;
		}else if(criterios==null || criterios.size()==0){
			logger.debug(" Se aplcia el filgro automatica si no existe criterio de filtro [{}]",criterios!=null?criterios.size():criterios);
			valdev=true;
		}else{
			List<Boolean> resutaldoCondiciones=new ArrayList<Boolean>();
			for(FiltroCriterio criterio:criterios){
				resutaldoCondiciones.add(filtrar(elemento,criterio,registros));
			}
			
			valdev=procesarCondicionales(criterios,resutaldoCondiciones);
			
		}
		return valdev;
	}
	
	/**
	 * 
	 * Se encarga de mirar si los criterios y sus resultados cumple los datos.
	 * 
	 * Nota: Queda pendiente de montar un condicional por parentesis, añadiendo un tema de criterios.	  
	 * 
	 * @param criterios				Los criterios de filtro.
	 * @param resultadoCondiciones	El resutlado de los filtros
	 * @return
	 * @throws ExceptionDbp 
	 */
	protected Boolean procesarCondicionales(List<FiltroCriterio> criterios,List<Boolean> resultadoCondiciones) throws ExceptionDbp{
		
		Boolean valdev=true;
		Integer i=0;
		for(FiltroCriterio criterio:criterios){
			logger.debug("La condicion [{}] la i [{}]",resultadoCondiciones.get(i),i);
			if(i==0){
				valdev=resultadoCondiciones.get(i);
			}else{
				if(criterios.get(i-1).getRelacional()==null){
					ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
							mensajeErrorFiltrarCriteriosOperacionRelacionalNoValida,criterio.getRelacional());
				}else{
					switch(criterios.get(i-1).getRelacional()){
						case O:{
							valdev=operacionO(valdev,resultadoCondiciones.get(i));
							break;
						}
						case Y:{
							valdev=operacionY(valdev,resultadoCondiciones.get(i));
							break;
						}
						default:{
							ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
									mensajeErrorFiltrarCriteriosOperacionRelacionalNoValida,criterio.getRelacional());
						}
					}
				}
			}
			i++;
		}
		return valdev;
	}
	/**
	 * Aplicamos la operación or entre el lado derecho y izquierdo
	 * @param izquierdo	Es la parte izquierda de la 
	 * @param derecho
	 * @return
	 */
	protected Boolean operacionO(Boolean izquierdo,Boolean derecho){
		return izquierdo || derecho;
	}
	/**
	 * Aplicamos la peracio anda entre el lado derecho y izquierdo.
	 * @param izquierdo
	 * @param derecho
	 * @return
	 */
	protected Boolean operacionY(Boolean izquierdo,Boolean derecho){
		return izquierdo && derecho;
	}
	
	
	
	/**
	 * 
	 * Se encarga de mirar si el elemento cumple el criterio
	 * 
	 * Nota, si no tiene elemento o criterio, la operacion se filtra.
	 * 
	 * Si el valor del filtro es null o vacio, la operación falta el filtro, de todos modos esto es revisable.
	 * 
	 * @param elemento		El elemento al que vamos aplicar el filtro en cuestión.
	 * @param criterio		El criterio que le vamos aplciar a la entidad.
	 * @param registros		Cache donde guardamos los PropertyEditorSupport asociadas a las clases para realizar las conversiones.
	 * @return
	 * @throws ExceptionDbp : Controla los siguientes errores:
	 * 	- El error al obtener el valor de un campo no valido.
	 *  - Error cuando usamos un campo que no cumple las condiciones para ser comparable. 
	 */
	public Boolean filtrar(T elemento,FiltroCriterio criterio,Map<Class,PropertyEditorSupport> registros) throws ExceptionDbp{
		Boolean valdev=false;
		if(elemento==null ){
			logger.debug(" Se aplica el filtro automaticamente si no existe la tupla [{}]",elemento);
			valdev=true;
		}else if(criterio==null){
			logger.debug(" Se aplcia el filgro automatica si no existe criterio de filtro [{}]",criterio);
			valdev=true;
		}else{
			if(registros==null){
				logger.info("Instanciamos los registros, ya que vamos a controlar con elementos y contenidos los posibles errores.");
				registros=new HashMap<Class,PropertyEditorSupport>();
			}
			Object valorCampo = obtenerElValorDelCampo(elemento, criterio);
			if(isCampoValidoFiltro(registros, valorCampo)){
				if(isCriterioValido(criterio, registros.get(valorCampo.getClass()))){
					valdev=filtrarCampo((Comparable)valorCampo,criterio,registros);
				}else{
					logger.warn("El criterio [{}] no tiene los valores correctos"
							,criterio!=null?
							ToStringBuilder.reflectionToString(criterio)
							:criterio);
					logger.warn("   - El error se ha producido en el campo [{}] con el valor [{}]",criterio.getCampo(),valorCampo);
					logger.warn("   - Que tiene el tipo de dato [{}]",valorCampo.getClass());
					ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
							mensajeErrorFiltrarCriteriosNoValidos,criterio.getCampo());
				}
			}else{
				// TODO Pendiente de implementar el caso de las cadenas de texto.
				/**
				 * Ideas:
				 *	Si existe el valor, pero lo complicado es que no es un tipo comparable, la idea seria pasarlo a una cadena de string.
				 */
				logger.warn("El campo [{}] no se puede comparar por el siguiente tipo de datos [{}] ",criterio.getCampo(),valorCampo!=null?valorCampo.getClass():valorCampo );
				logger.warn("   - El valor del campo, que hivamos a filtrar es el siguiente [{}]",valorCampo);
				logger.warn("   - Aplicando el criterio [{}]"
						,criterio!=null?
								ToStringBuilder.reflectionToString(criterio)
								:criterio);
				logger.warn("   - Si necesita filtrar por este campo, haga la clase del campo Comparable y añadale a la cache (con el property editor correspondiente.)");
				ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
						mensajeErrorFiltrarObtenerCampoNoValido,criterio.getCampo(),elemento.getClass());
			}
		}
		return valdev;
	}
	/**
	 * 
	 * @param criterio
	 * @param registro
	 * @return
	 */
	protected boolean isCriterioValido(FiltroCriterio criterio,
			PropertyEditorSupport registro) {
		Boolean valdev=
				criterio!=null 
				&& registro!=null
				&& criterio.getOperacion()!=null;
		if(valdev && StringUtils.isNotBlank(criterio.getValorFiltro())){
			try{
				registro.setAsText(criterio.getValorFiltro());
			}catch(Throwable e){
				logger.warn("No se puede aplicar el criterio, por el valor de filtro no es valido  por el siguiente error [{}]",e.getMessage(),e);
				valdev=false;
			}
		}
		return valdev;
	}
	/**
	 * 
	 * Nos indica si el campo que vamos a utilzar cumple las condiciones.
	 * 	- Que se comparable.
	 *  - Este añadido a la lista de propertyEditorSuport.
	 *  
	 * @param registros		La cache donde se hah registrado los property editors.
	 * @param valorCampo	El valor del campo.
	 * @return
	 */
	protected boolean isCampoValidoFiltro(
			Map<Class, PropertyEditorSupport> registros, Object valorCampo) {
		return valorCampo!=null 
				&& valorCampo instanceof Comparable
				&& registros!=null
				&& registros.containsKey(valorCampo.getClass());
	}

	/**
	 * 
	 * Este método se encarga de obtener el valor del campo, que esta definido en el criterio.
	 * 
	 * @param elemento	Sobre la tupla con la que vamos a trabajar.
	 * @param criterio	El criterio que vamos a aplicar.
	 * @return
	 * @throws ExceptionDbp
	 */
	private Object obtenerElValorDelCampo(T elemento, FiltroCriterio criterio) throws ExceptionDbp {
		Object valorCampo = null;
		try {
			valorCampo=PropertyUtils.getProperty(elemento,criterio.getCampo());
		} catch (IllegalArgumentException|IllegalAccessException | InvocationTargetException
				| NoSuchMethodException e) {
			ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger,e, 
					mensajeErrorFiltrarObtenerElCampo,criterio.getCampo(),elemento.getClass());
		}
		return valorCampo;
	}
	
	
	
	/**
	 * 
	 * Nos indica si el campo que le pasamos cumple o no el criterio.
	 * 
	 * @param valorCampo	El valor del campo que vamos a filtrar.
	 * @param criterio		El criterio que vamos aplicar.
	 * @param registros		Cache donde guardamos los PropertyEditorSupport asociadas a las clases para realizar las conversiones.
	 * @return
	 * @throws ExceptionDbp
	 */
	protected <C extends Comparable<C>> Boolean filtrarCampo(C valorCampo,FiltroCriterio criterio,Map<Class,PropertyEditorSupport> registros) throws ExceptionDbp{
		Boolean valdev=false;
		if(criterio==null){
			ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
					mensajeErrorFiltrarCampoNoHayCriterios,criterio);

		}else if(criterio.getOperacion()==null){
			ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
					mensajeErrorFiltrarCampoNoHayOperacion,criterio.getOperacion());
		}else{
			C valorFiltro = obtenerValor(criterio.getValorFiltro(), (Class<C>)valorCampo.getClass(), registros);
			valdev = procesarFiltrarCampo(valorCampo,valorFiltro, criterio,registros.get((Class<C>)valorCampo.getClass()));
		}
		return valdev;
	}
	/**
	 * Se encarga de procesar el filtro del campo.
	 * @param valorCampo	El valor del campo con el que vamos a trabajar.
	 * @param valorFiltro	El valor del filtro que vamos aplicar al campo en cuestión.
	 * @param criterio		El criterio, que vamos aplicar.
	 * @param registros		Hay casos en los que tendremos que volver hacia atras.
	 * @return
	 */
	private <C extends Comparable<C>> Boolean procesarFiltrarCampo(
			C valorCampo, C valorFiltro, FiltroCriterio criterio,PropertyEditorSupport propertyEditorSupport) {
		 Boolean valdev=false;
		switch(criterio.getOperacion()){
			case IGUAL:{
				valdev=operaionIgual(valorCampo, valorFiltro);
				break;
			}
			case NO_IGUAL:{
				valdev=!operaionIgual(valorCampo,valorFiltro);
				break;
			}
			case MAYOR:{
				valdev=operaionMayor(valorCampo, valorFiltro, false);
				break;
			}
			case MAYOR_IGUAL:{
				valdev=operaionMayor(valorCampo, valorFiltro, true);
				break;
			}

			case MENOR:{
				valdev=operaionMenor(valorCampo, valorFiltro, false);
				break;
			}
			case MENOR_IGUAL:{
				valdev=operaionMenor(valorCampo, valorFiltro, true);
				break;
			}
			case EMPIEZA_POR:{
				valdev=contiene(valorCampo, valorFiltro, false,TipoOperacionContiene.EMPIEZA, propertyEditorSupport);
				break;
			}
			case NO_EMPIEZA_POR:{
				valdev=!contiene(valorCampo, valorFiltro, false,TipoOperacionContiene.EMPIEZA, propertyEditorSupport);
				break;
			}
			case TERMINA_EN:{
				valdev=contiene(valorCampo, valorFiltro, false,TipoOperacionContiene.TERMINA, propertyEditorSupport);
				break;
			}
			case NO_TERMINA_EN:{
				valdev=!contiene(valorCampo, valorFiltro, false,TipoOperacionContiene.TERMINA, propertyEditorSupport);
				break;
			}
			case CONTIENE:{
				valdev=contiene(valorCampo, valorFiltro, false,TipoOperacionContiene.CONTIENE, propertyEditorSupport);
				break;
			}
			case NO_CONTIENE:{
				valdev=!contiene(valorCampo, valorFiltro, false,TipoOperacionContiene.CONTIENE, propertyEditorSupport);
				break;
			}
			default:{
				logger.debug("La operación [{}] no esta entre la disponibles para filtrar ",criterio.getOperacion());
			}
		}
		return valdev;
	}
	
	public enum TipoOperacionContiene{
		EMPIEZA,
		TERMINA,
		CONTIENE
	}
	
	/**
	 * Se encarga de validar que un campo empieza por el texto que le han pasado.
	 * 
	 * @param valorCampo			El valor del campo, del objeto con el que vamos a trabajar.
	 * @param valorFiltro			El valor del filtro, con el que vamos a trabajar.
	 * @param ignoreCase			Nos indica si tenemos que ignorar o no las mayuscalas.
	 * @param propertyEditorSupport	La herramienta para realizar las conversiones.
	 * 
	 * @return	Nos indica si empieza por.
	 */
	protected <C extends Comparable<C>> Boolean contiene(C valorCampo,C valorFiltro,Boolean ignoreCase,TipoOperacionContiene tipo,PropertyEditorSupport propertyEditorSupport){
		Boolean valdev= false;
		logger.debug("INICIO: Empieza por");
		if(valorCampo!=null && valorFiltro!=null){
		  propertyEditorSupport.setValue(valorCampo);
		  String valorCampoCadena=propertyEditorSupport.getAsText();
		  propertyEditorSupport.setValue(valorFiltro);
		  String valorFiltroCadena=propertyEditorSupport.getAsText();
		  logger.debug(" - El valorCampo [{}] su representacion en texto es:[{}]"
				  ,valorCampo,valorCampoCadena);
		  logger.debug(" - El valorFiltro[{}] su representacion en texto es[{}]"
				  ,valorFiltro,valorFiltroCadena);
		  valdev = procesarTipoOperacionContiene(ignoreCase, tipo,	valorCampoCadena, valorFiltroCadena);
		}else if(valorCampo!=null && valorFiltro==null){
			logger.debug("Al no tener un valor de filtro lo entendemos como una cadena vacia, y siempre sera verdadero");
			valdev=true;
		}else if(valorCampo==null && valorFiltro!=null){
			
  		    propertyEditorSupport.setValue(valorFiltro);
			String valorFiltroCadena=propertyEditorSupport.getAsText();
			logger.debug("Si no tenemos en el campo, no puede empezar nunca por nada, salvo el nulo o la cadena vacia. Valor filtro [{}] en cadena [{}]",valorFiltro,valorFiltroCadena);
			valdev=StringUtils.isBlank(valorFiltroCadena);
		}else{
			logger.debug("Al no tener el filtro valor, prevale sobre el valor por que estamos marcando que se filtren todos.");
			valdev=true;
		}
		logger.debug("FIN: Empieza por valdev[{}]",valdev);
		return valdev;
	}
	/**
	 *	
	 * Se encarga de realizar la operación de contiene, cuando tenemos los 2 valores.
	 * 
	 * Nota: Este método va atado a otra operación que se encarga de validar que los valores sean los correctos.
	 * 
	 * @param ignoreCase		Nos indica si tenemos que ignorar o no las mayuscalas.
	 * @param tipo				Nos indica el tipo de contenido (Normal, Inicio, Final).
	 * @param valorCampoCadena	Valor del campo.
	 * @param valorFiltroCadena	El valor del filtro de la cadena.
	 * @return
	 */
	private Boolean procesarTipoOperacionContiene(Boolean ignoreCase,TipoOperacionContiene tipo,String valorCampoCadena, String valorFiltroCadena) {
		Boolean valdev=false;
		switch(tipo){
		  case EMPIEZA:{
			  if(ignoreCase!=null && ignoreCase){
				  valdev=StringUtils.startsWithIgnoreCase(valorCampoCadena, valorFiltroCadena);
			  }else{
				  valdev=StringUtils.startsWith(valorCampoCadena, valorFiltroCadena);
			  }

			  break;
		  }
		  case TERMINA:{
			  if(ignoreCase!=null && ignoreCase){
				  valdev=StringUtils.endsWithIgnoreCase(valorCampoCadena, valorFiltroCadena);
			  }else{
				  valdev=StringUtils.endsWith(valorCampoCadena, valorFiltroCadena);
			  }
			  break;
		  }
		  case CONTIENE:{
			  if(ignoreCase!=null && ignoreCase){
				  valdev=StringUtils.containsIgnoreCase(valorCampoCadena, valorFiltroCadena);
			  }else{
				  valdev=StringUtils.contains(valorCampoCadena, valorFiltroCadena);
			  }
			  break;
		  }
		  }
		return valdev;
	}
	
	/**
	 * 
	 * Mira si dos campos son iguales.
	 * 
	 * @param valorCampo	El valor del campo
	 * @param valorFiltro	Esta incluido el valor del filtro.
	 * @return
	 */
	protected <C extends Comparable<C>> Boolean operaionIgual(C valorCampo,C valorFiltro){
		Boolean valdev=false;
		if(valorCampo!=null 
		    && valorFiltro!=null
			){
			valdev= valorCampo.equals(valorFiltro);
		}else{
			valdev=valorCampo==valorFiltro;
		}
		return valdev;
	}
	/**
	 * 
	 * Mira si el valor del campo es mayor que el que nos pasan 
	 * en el filtro.
	 * 
	 * @param valorCampo	El valor que tiene el campo.
	 * @param valorFiltro	El valor que tiene el filtro
	 * @param incluidoElIgual	Nos indica si el valor esta incluido.
	 * @return
	 */
	protected <C extends Comparable<C>> Boolean operaionMayor(C valorCampo,C valorFiltro,Boolean incluidoElIgual){
		return operacionComparate(valorCampo, valorFiltro, incluidoElIgual);
	}
	/**
	 * Mirar si el valor del campo es menos que el que nos pasan en el filtro.
	 * @param valorCampo	El valor que tiene el campo.
	 * @param valorFiltro	El valor que tiene el filtro.
	 * @param incluidoElIgual	Nos indica si el valor esta incluido.
	 * @return
	 */
	protected <C extends Comparable<C>> Boolean operaionMenor(C valorCampo,C valorFiltro,Boolean incluidoElIgual){
		return operacionComparate( valorFiltro,valorCampo, incluidoElIgual);
	}
	
	/**
	 * 
	 * Este método se encarga de obtener el valor de la cadena de texto que nos han pasado.
	 * 
	 * @param valorFiltro		El valor del filtro.
	 * @param clase				La clase con la que vamos a filtrar la operación.
	 * @param registros			Cache donde guardamos los registros asociadas a las clases que son comprarables (Implementan la interfaz comparable).
	 * @return	Nos devuelve el objeto que representa la cadena de texto.
	 * @throws ExceptionDbp
	 */
	protected <C extends Comparable<C>> C obtenerValor(String valorFiltro,Class<C> clase,Map<Class,PropertyEditorSupport> registros) throws ExceptionDbp{
		C valdev=null;
		if(registros==null||registros.size()==0){
			ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
					mensajeErrorObtenerValorRegistroVacio,registros!=null?registros.size():registros);
		}else if(clase==null){
			ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
					mensajeErrorObtenerValorClaseVacia,clase);
		}else if(!registros.containsKey(clase)){
			ErrorDbpUtils.obtenerInstancia().procesarErrorClave(logger, 
					mensajeErrorObtenerValorNoEncontradaLaClase,clase);
		}else{
			PropertyEditorSupport propertyEditorSupport=registros.get(clase);
			propertyEditorSupport.setAsText(valorFiltro);
			valdev=(C)propertyEditorSupport.getValue();
		}
		return valdev;
	}
	
	/**
	 * Método encargado de trabajar con el comparate.
	 * 
	 * @param valorIzquierda
	 * @param valorDerecha
	 * @param incluidoElIgual
	 * @return
	 */
	private <C extends Comparable<C>> Boolean operacionComparate(C valorIzquierda,
			C valorDerecha, Boolean incluidoElIgual) {
		Boolean valdev=false;
		if(valorIzquierda!=null
				&& valorDerecha!=null){
			if(incluidoElIgual!=null
					&& incluidoElIgual){
				valdev=valorIzquierda.compareTo(valorDerecha)>=0;
			}else{
				valdev=valorIzquierda.compareTo(valorDerecha)>0;
			}
		}else if(incluidoElIgual!=null
				&& incluidoElIgual){
			valdev=valorIzquierda==valorDerecha;
		}
			
		return valdev;
	}
}
